# -*- coding: utf-8 -*-

#给实例动态绑定实例
class Student(object):
    pass
s=Student()
#绑定属性
s.name="bob"
print(s.name)

#绑定方法 对另一个实例不起作用
def set_age(self,age):
    self.age=age
from types import MethodType
s.set_age=MethodType(set_age,s)
#掉用实例方法
s.set_age(23)
print(s.age)

#为了给所有实例都绑定方法，可以给class绑定方法
def set_score(self, score):
    self.score = score
Student.set_score=set_score
#调用
s.set_score(100)
print(s.score)


#__slots__ 如果我们想要限制实例的属性怎么办？比如，只允许对Student实例添加name和age属性。使用一个tulpe来限制
class Student(object):
    __slots__ = ('name', 'age')
s=Student()
#不允许绑定
#s.score=90






#Python内置的@property装饰器就是负责把一个方法变成属性调用的： 
#@property把一个setter变为属性 此时，@property本身又创建了另一个装饰器@score.setter，负责把一个setter方法变成属性赋值，
class Student(object):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

s=Student()
s.score=100 #相当于s.score(100)
s.score # 实际转化为s.get_score()



#多重继承
class Animal(object):
    pass
class CanFly(Animal):
    pass
class CanRun(Animal):
    pass
class Bird(CanFly,CanRun):
    pass



#定制类 比如__slots__  __xxx__的变量或者函数名就要注意，这些在Python中是有特殊用途

#__str__ 相当于重写toString 方法

class Student(object):
    def __init__(self,name):
        self.__name=name

    def __str__(self):
        return '{名字：%s}' %(self.__name)

print(Student('bob'))
s=Student('dave')
print(s)



#__iter__ 相当于java iterator接口 让一个类具有迭代
#__iter__方法返回一个迭代对象 python的for循环就会不断调用迭代对象的__next__()方法拿到循环的下一个值
class Fib(object):
    def __init__(self):
        self.a,self.b=0,1
    def __iter__(self):
        return self
    def __next__(self):
        self.a, self.b = self.b, self.a + self.b # 计算下一个值
        if self.a > 100000: # 退出循环的条件
            raise StopIteration()
        return self.a # 返回下一个值

#打印斐波那契
for n in Fib():
    print(n)




#__getitem__
#__iter__使元素具有了像list一样的迭代 但还是不能按索引取
# print(Fib()[0])

class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a

print(Fib()[1])



#__getattribute__ 如果调用一个属性不存在就会报错 加上__getattribute__会在里面去找
class Student(object):
    def __init__(self,name):
        self.__name=name
    def __getattribute__(self,attr):
        if attr=='score':
            return 99
s=Student("dave")
#找不到就去__getattribute__里面找
print(s.score)


#自动生成api url
class Chain(object):

    def __init__(self, path=''):
        self._path = path

    def __getattr__(self, path):
        return Chain('%s/%s' % (self._path, path))

    def __str__(self):
        return self._path

    __repr__ = __str__

print(Chain().status.user.list)


#__call__ 实例调用自己本身
class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)

s=Student("dave")
#调用自己本身
s()
#这种方式会模糊对象和函数的概念 
# 我们需要判断一个对象是否能被自身调用，能被自身调用的对象就是一个Callable对象，比如函数和我们上面定义的带有__call__()的类实例：
print("能被自身调用吗：",callable(Student("gg")))



#枚举类型
from enum import Enum
Month=Enum('Month',('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
#引用枚举
print(Month.Jan)

#value属性则是自动赋给成员的int常量，默认从1开始计数。
for name,member in Month.__members__.items():
    print(name, '=>',',',member.value)

#可以从Enum派生类
from enum import Enum, unique
@unique
class Weekday(Enum):
    Sun = 0 # Sun的value被设定为0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6
#@unique装饰器可以帮助我们检查保证没有重复值。

day1=Weekday.Sun

print(day1)


#